import core.Handler;
import core.RequestMappingAdapter;
import core.SingletonFactory;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import static config.ServerConfig.*;

/**
 * Server一直监听指定端口，每次建立一个短的TCP连接，应用层采用Java自带的对象序列化协议。客户端发送一个Request，服务器回应一个Response后就释放该连接
 * <dl>
 *     <dt>Server工作流程</dt>
 *     <dd>1. 接受新的客户端连接，创建一个新Socket</dd>
 *     <dd>2. 创建一个新的Handler，将该Socket交给Handler处理</dd>
 * </dl>
 *
 * @see Handler
 */
public class Server {

    private static int port = DEFAULT_SERVER_PORT;

    public static void main(String[] args) {
        parseArgs(args);
        init();

        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(MINIMUM_POOL_SIZE, MAXIMUM_POOL_SIZE,
            THREAD_KEEP_ALIVE_TIME.toMillis(), TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(LINKED_BLOCKING_QUEUE_CAPACITY)); // create thread pool

        try (ServerSocket serverSocket = new ServerSocket(port)) {
            System.out.println("server: now listening on port " + port);
            while (true) { // endless loop for accepting new connection
                Socket accept = serverSocket.accept();
                accept.setSoTimeout(SOCKET_TIMEOUT_MILLIS);
                threadPool.execute(new Handler(accept));
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static void parseArgs(String[] args) {
        for (int i = 0; i < args.length; ) {
            String arg = args[i];
            switch (arg) {
                case "--port": {
                    port = Integer.parseInt(args[i + 1]);
                    i += 2;
                    break;
                }
                default: {
                    throw new RuntimeException("parseArgs: Illegal argument");
                }
            }
        }
    }

    private static void init() {
        // execute static block
        try {
            Class.forName(SingletonFactory.class.getName());
            Class.forName(RequestMappingAdapter.class.getName());
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("init: static block fail");
        }
    }
}
